import { Robot, Group, Animate } from "leafer-game";
import { Bounds } from "leafer-ui";
import { registerUI, Leafer } from "@leafer-ui/core";
import { Keyboard } from "../physics-engine/keyboard";
import { Collider } from '../collider';
// import { Camera } from "../camera";
import type { ILeafer } from '@leafer-ui/interface';
import { HEIGHT, PlayerInfo, WIDTH } from '../global';
import type { Collidable } from "../interface";

type Point = { x: number; y: number };

const playerWalkSprites = [0, 1, 2, 3, 4, 5]
const playerAttackSprites = [36, 37, 38, 39]
const DIRECTION_X = ['ArrowLeft', 'ArrowRight']
const DIRECTION_Y = ['ArrowUp', 'ArrowDown']
const DIRECTION_KEYS = [...DIRECTION_X, ...DIRECTION_Y]

@registerUI()
export class Player extends Leafer {
    keyboard: Keyboard;
    player: Robot;
    collider: Collider;
    group: Group;
    // _camera: Camera;
    _SPEED = 2;
    _vx = 0;
    _vy = 0;
    _lastDirection = '';
    _attacking = false;
    _walking = false;
    public get __tag() { return 'Player' }
    _attaclAnimateMap: Record<string, Animate> = {}
    collisionType: string = '';
    localX = 0;
    localY = 0;
    ground: ILeafer;
    _width = 32;
    _height = 32;
    _centerX = (WIDTH / 2 - this._width / 2);
    _centerY = (HEIGHT / 2 - this._height / 2);
    _cameraOffset = 30;
    constructor(ground: ILeafer) {
        super()
        this.ground = ground;
        this.group = new Group({
            width: this._width,
            height: this._height,
        })
        this.collider = new Collider({
            width: 18,
            height: 24,
            offsetX: 7,
            offsetY: 3,
            colloderInfo: {
                instance: this,
                type: 'char'
            }
        })
        this.player = new Robot({
            tag: 'Player',
            robot: { url: '/Player/Player.png', size: { width: this._width, height: this._height }, total: 60 },
            actions: {  // 预设游戏动作（通过动作帧）
                idleArrowDown: playerWalkSprites,
                idleArrowRight: playerWalkSprites.map((i) => i + 6),
                idleArrowLeft: playerWalkSprites.map((i) => i + 6),
                idleArrowUp: playerWalkSprites.map((i) => i + 12),
                walkArrowDown: playerWalkSprites.map((i) => i + 18),
                walkArrowRight: playerWalkSprites.map((i) => i + 24),
                walkArrowLeft: playerWalkSprites.map((i) => i + 24),
                walkArrowUp: playerWalkSprites.map((i) => i + 30),
                attackArrowDown: playerAttackSprites,
                attackArrowRight: playerAttackSprites.map((i) => i + 6),
                attackArrowLeft: playerAttackSprites.map((i) => i + 6),
                attackArrowUp: playerAttackSprites.map((i) => i + 12),
                die: playerAttackSprites.map((i) => i + 18),
            },
            // action: 'idleArrowUp' // 设置默认动作
        })

        this.group.add([this.collider, this.player])
        super.add(this.group);
        this.keyboard = new Keyboard();
        const attackArrowDownAnimate = new Animate(this.player,
            { action: 'attackArrowDown' },
        )
        const attackArrowRightAnimate = new Animate(this.player,
            { action: 'attackArrowRight' },
        )
        const attackArrowLeftAnimate = new Animate(this.player,
            { action: 'attackArrowLeft' },
        )
        const attackArrowUpAnimate = new Animate(this.player,
            { action: 'attackArrowUp' },
        )
        this._attaclAnimateMap = {
            attackArrowDownAnimate,
            attackArrowRightAnimate,
            attackArrowLeftAnimate,
            attackArrowUpAnimate
        }
        // this._camera = new Camera();
        PlayerInfo.player = this;
    }

    setActionClosure = (pressKey: string) => {
        let cachePressKey = pressKey;
        return (pressKey?: string) => {
            const validKey = pressKey ?? cachePressKey;
            cachePressKey = validKey;
            const actionTyle = pressKey ? 'walk' : 'idle';
            const action = actionTyle + validKey
            this.player.action = action;
        }
    }

    setAction = this.setActionClosure('ArrowDown')

    attack = () => {
        const attackAnimate = 'attack' + this._lastDirection + 'Animate'
        this._attaclAnimateMap[attackAnimate]?.play()
    }

    moveMap: Record<string, (isPressing: boolean) => void> = {
        KeyA: this.attack,
    }

    get isAttacking() {
        const action = this.player.action ?? ''
        return action.indexOf('attack') > -1
    }

    get isWalking() {
        const action = this.player.action ?? ''
        return action.indexOf('walk') > -1
    }

    handleAttack = ({ pressKey }: {
        pressKey: string,
    }) => {
        const actions = this.player.actions?.[this.player.action ?? ''] as number[];
        const now = this.player.now;
        const lastAction = actions[actions.length - 1];
        if (now === lastAction) {
            this.player.action = 'idle' + (pressKey ?? this._lastDirection)
        }
    }

    _move = (lastPressKey?: string) => {
        if ((this.player.scaleX === 1 && lastPressKey === 'ArrowLeft') || (this.player.scaleX === -1 && lastPressKey === 'ArrowRight')) {
            this.player.flip('x');
        }
        this._vx = lastPressKey === 'ArrowLeft' ? -this._SPEED : lastPressKey === 'ArrowRight' ? this._SPEED : 0;
        this._vy = lastPressKey === 'ArrowUp' ? -this._SPEED : lastPressKey === 'ArrowDown' ? this._SPEED : 0;

        const staticColliders = Collider.staticColliders();

        const canMove = !staticColliders.some((coll) => this.collisionCheck(coll));

        if (canMove) {
            const { x: groupX = 0, y: groupY = 0 } = this.group;
            const { x: groundX = 0, y: groundY = 0 } = this.ground;
            const nextGroupX = groupX + this._vx;
            const nextGroupY = groupY + this._vy;

            const isBgEdgeXLeft = groundX === 0;
            const isBgEdgeXRight = groundX === -window.innerWidth + WIDTH;
            const isBgEdgeYTop = groundY === 0;
            const isBgEdgeYBottom = groundY === -window.innerHeight + HEIGHT;

            let validGroupX = groupX;
            let validGroupY = groupY;

            if (nextGroupX > this._centerX) {
                if (isBgEdgeXRight) {
                    validGroupX = groupX + this._vx;
                } else {
                    validGroupX = this._centerX;
                }
            } else {
                if (isBgEdgeXLeft) {
                    validGroupX = groupX + this._vx;
                } else {
                    validGroupX = this._centerX;

                }
            }

            if (nextGroupY > this._centerY) {
                if (isBgEdgeYBottom) {
                    validGroupY = groupY + this._vy;
                } else {
                    validGroupY = groupY;
                }
            } else {
                if (isBgEdgeYTop) {
                    validGroupY = groupY + this._vy;
                } else {
                    validGroupY = groupY;
                }
            }

            if (nextGroupX >= WIDTH - 24) {
                validGroupX = WIDTH - 24;
            } else if (nextGroupX < 0) {
                validGroupX = 0;
            }

            if (nextGroupY >= HEIGHT - 24) {
                validGroupY = HEIGHT - 24;
            } else if (nextGroupY < 0) {
                validGroupY = 0;
            }
            const hasMoveX = validGroupX !== groupX;
            const hasMoveY = validGroupY !== groupY;

            this.group.x! = validGroupX;
            this.group.y! = validGroupY;

            const nextGroundX = hasMoveX ? groundX : groundX - this._vx;
            const nextGroundY = hasMoveY ? groundY : groundY - this._vy;

            const validGroudX = nextGroundX >= 0 ? 0 : nextGroundX <= -window.innerWidth + WIDTH ? -window.innerWidth + WIDTH : nextGroundX;
            const validGroudY = nextGroundY >= 0 ? 0 : nextGroundY <= -window.innerHeight + HEIGHT ? -window.innerHeight + HEIGHT : nextGroundY;
            this.ground.x! = validGroudX;
            this.ground.y! = validGroudY;
        }
    }

    isPointInRange = (target: Point, leftTop: Point, rightBottom: Point) => {
        const { x: tX, y: tY } = target;
        const { x: lX, y: lY } = leftTop;
        const { x: rX, y: rY } = rightBottom;
        return tX >= lX && tX <= rX && tY >= lY && tY <= rY
    }

    run = (trees) => {
        const { pressKey, pressKeys } = this.keyboard;
        if (this.isAttacking) {
            this.handleAttack({ pressKey: pressKey ?? this._lastDirection })
            return;
        }
        const lastPressKey = pressKeys[pressKeys.length - 1]
        if (lastPressKey && DIRECTION_KEYS.includes(lastPressKey)) {
            this._lastDirection = lastPressKey;
        }

        this._move(lastPressKey);
        this.setAction(lastPressKey);
    }

    collisionCheck = (collider: Collidable) => {
        const playerBound = new Bounds(this.nextFrameBoxBounds);
        const collision = playerBound.hit(collider.collider.worldBoxBounds)
        if (collision) {
            this.onHit(collider.collider)
        }
        return collision;
    }

    onHit = (collider: Collider) => {
        this.collisionType = collider.type;
        console.log(collider.parent)
    }

    get bounds() {
        return new Bounds(this.collider.worldBoxBounds);
    }

    get nextFrameBoxBounds() {
        return {
            x: (this.collider.worldBoxBounds.x ?? 0) + this._vx,
            y: (this.collider.worldBoxBounds.y ?? 0) + this._vy,
            width: this.collider.width ?? 0,
            height: this.collider.height ?? 0,
        }
    }
}